From c0e159b6ade0880b574dd4baf15117791c70b809 Mon Sep 17 00:00:00 2001 From: oliskoli Date: Thu, 11 Sep 2008 20:40:33 +0000 Subject: [PATCH] gbfile: Add wrappers for each specific file api (standard, gzlib, AND memory). A 'memory only' gbfile can be created with 'gbfopen(NULL, "w", MYNAME)'. git-svn-id: http://gpsbabel.googlecode.com/svn/trunk@3481 f51c46e8-681c-474f-0cfe-069cfd0219fb --- gpsbabel/gbfile.c | 780 ++++++++++++++++++++++++++++++---------------- gpsbabel/gbfile.h | 40 ++- 2 files changed, 544 insertions(+), 276 deletions(-) diff --git a/gpsbabel/gbfile.c b/gpsbabel/gbfile.c index bf450791b..bec1cf55c 100644 --- a/gpsbabel/gbfile.c +++ b/gpsbabel/gbfile.c @@ -1,7 +1,8 @@ /* Common GPSBabel file I/O API - Copyright (C) 2006 Olaf Klein, o.b.klein@gpsbabel.org + + Copyright (C) 2006,2007,2008 Olaf Klein, o.b.klein@gpsbabel.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -50,6 +51,410 @@ * */ + +/*******************************************************************************/ +/* %%% file api wrappers %%% */ +/*******************************************************************************/ + +#if !ZLIB_INHIBITED + +/*******************************************************************************/ +/* %%% Zlib file api %%% */ +/*******************************************************************************/ + +static gbfile * +gzapi_open(gbfile *self, const char *mode) +{ + char openmode[32]; + + self->gzapi = 1; + + /* under non-posix systems files MUST be opened in binary mode */ + + strcpy(openmode, mode); + if (strchr(mode, 'b') == NULL) + strncat(openmode, "b", sizeof(openmode)); + + if (self->is_pipe) { + FILE *fd; + if (self->mode == 'r') + fd = stdin; + else + fd = stdout; + SET_BINARY_MODE(fd); + self->handle.gz = gzdopen(fileno(fd), openmode); + } + else + self->handle.gz = gzopen(self->name, openmode); + + if (self->handle.gz == NULL) { + fatal("%s: Cannot %s file '%s'!\n", + self->module, + (self->mode == 'r') ? "open" : "create", + self->name); + } + + return self; +} + +static int +gzapi_close(gbfile *self) +{ + return gzclose(self->handle.gz); +} + +static int +gzapi_seek(gbfile *self, gbint32 offset, int whence) +{ + int result; + + assert(whence != SEEK_END); + + if ((whence == SEEK_CUR) && (self->back != -1)) offset--; + result = gzseek(self->handle.gz, offset, whence); + self->back = -1; + + if (result < 0) { + if (self->is_pipe) + fatal("%s: This format cannot be used in piped commands!\n", self->module); + fatal("%s: online compression not yet supported for this format!", self->module); + } + return 0; +} + +static gbsize_t +gzapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + int result = 0; + char *target = buf; + int count = size * members; + + if (self->back != -1) { + *target++ = self->back; + count--; + result++; + self->back = -1; + } + result += gzread(self->handle.gz, target, count); + + /* Check for an incomplete READ */ + if ((members == 1) && (size > 1) && (result > 0) && (result < (int)size)) + fatal("%s: Unexpected end of file (EOF)!\n", self->module); + + result /= size; + + if ((result < 0) || ((gbsize_t)result < members)) { + int errnum; + const char *errtxt; + + errtxt = gzerror(self->handle.gz, &errnum); + + /* Workaround for zlib bug: buffer error on empty files */ + if ((errnum == Z_BUF_ERROR) && (gztell(self->handle.gz) == 0)) { + return (gbsize_t) 0; + } + if ((errnum != Z_STREAM_END) && (errnum != 0)) + fatal("%s: zlib returned error %d ('%s')!\n", + self->module, errnum, errtxt); + } + return (gbsize_t) result; +} + +static gbsize_t +gzapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + return gzwrite(self->handle.gz, buf, size * members) / size; +} + +static int +gzapi_flush(gbfile *self) +{ + return gzflush(self->handle.gz, Z_SYNC_FLUSH); +} + +static gbsize_t +gzapi_tell(gbfile *self) +{ + gbsize_t result; + + result = gztell(self->handle.gz); + if (self->back != -1) result--; + + return result; +} + +static int +gzapi_eof(gbfile *self) +{ + int res = 0; + + if (self->back != -1) return res; + + res = gzeof(self->handle.gz); + if (!res) { + unsigned char test; + int len = gzread(self->handle.gz, &test, 1); + if (len == 1) { + /* No EOF, put the single byte back into stream */ + self->back = test; + } + else { + /* we are at the end of the file */ + if (global_opts.debug_level > 0) { + /* now gzeof() should return 1 */ + is_fatal(!gzeof(self->handle.gz), "zlib gzeof error!\n"); + } + res = 1; + } + } + return res; +} + +static int +gzapi_ungetc(const int c, gbfile *self) +{ + if (self->back == -1) + self->back = c; + else + fatal(MYNAME ": Cannot store more than one byte back!\n"); + return c; +} + +static void +gzapi_clearerr(gbfile *self) +{ + gzclearerr(self->handle.gz); +} + +static int +gzapi_error(gbfile *self) +{ + int errnum; + + (void)gzerror(self->handle.gz, &errnum); + + return errnum; +} +#endif // #if !ZLIB_INHIBITED + + +/*******************************************************************************/ +/* %%% Standard C file api %%% */ +/*******************************************************************************/ + +static gbfile * +stdapi_open(gbfile *self, const char *mode) +{ + self->handle.std = xfopen(self->name, mode, self->module); + return self; +} + +static int +stdapi_close(gbfile *self) +{ + return fclose(self->handle.std); +} + +static int +stdapi_seek(gbfile *self, gbint32 offset, int whence) +{ + int result; + gbsize_t pos = 0; + + if (whence != SEEK_SET) pos = ftell(self->handle.std); + + result = fseek(self->handle.std, offset, whence); + if (result != 0) { + switch (whence) { + case SEEK_CUR: + case SEEK_END: pos = pos + offset; break; + case SEEK_SET: pos = offset; break; + default: + fatal("%s: Unknown seek operation (%d) for file %s!\n", + self->module, whence, self->name); + } + fatal("%s: Unable to set file (%s) to position (%llu)!\n", + self->module, self->name, (long long unsigned) pos); + } + return 0; +} + +static gbsize_t +stdapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + int errno; + gbsize_t result = fread(buf, size, members, self->handle.std); + + if ((result < members) && (errno = ferror(self->handle.std))) { + fatal("%s: Error %d occured during read of file '%s'!\n", + self->module, errno, self->name); + } + return result; +} + +static gbsize_t +stdapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + return fwrite(buf, size, members, self->handle.std); +} + +static int +stdapi_flush(gbfile *self) +{ + return fflush(self->handle.std); +} + +static gbsize_t +stdapi_tell(gbfile *self) +{ + return ftell(self->handle.std); +} + +static int +stdapi_eof(gbfile *self) +{ + return feof(self->handle.std); +} + +static int +stdapi_ungetc(const int c, gbfile *self) +{ + return ungetc(c, self->handle.std); +} + +static void +stdapi_clearerr(gbfile *self) +{ + clearerr(self->handle.std); +} + +static int +stdapi_error(gbfile *self) +{ + return ferror(self->handle.std); +} + + +/*******************************************************************************/ +/* %%% Memory stream (memapi) %%% */ +/*******************************************************************************/ + +static gbfile * +memapi_open(gbfile *self, const char *mode) +{ + self->mempos = 0; + self->memsz = 0; + self->handle.mem = NULL; + + return self; +} + +static int +memapi_close(gbfile *self) +{ + xfree(self->handle.mem); + + return 0; +} + +static int +memapi_seek(gbfile *self, gbint32 offset, int whence) +{ + long long pos = (int)self->mempos; + + switch (whence) { + case SEEK_CUR: + case SEEK_END: pos = pos + offset; break; + case SEEK_SET: pos = offset; break; + } + + if ((pos < 0) || (pos > self->memlen)) return -1; + + self->mempos = pos; + return 0; +} + +static gbsize_t +memapi_read(void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + gbsize_t count; + gbsize_t result = (self->memlen - self->mempos) / size; + + if (result > members) result = members; + count = result * size; + if (count) { + memcpy(buf, self->handle.mem + self->mempos, count); + self->mempos += count; + } + + return result; +} + +static gbsize_t +memapi_write(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self) +{ + gbsize_t count; + + if ((size == 0) && (members == 0)) { /* truncate stream */ + self->memlen = self->mempos; + return 0; + } + + count = size * members; + + if (self->mempos + count > self->memsz) { + self->memsz = ((self->mempos + count + 4095) / 4096) * 4096; + self->handle.mem = xrealloc(self->handle.mem, self->memsz); + } + memcpy(self->handle.mem + self->mempos, buf, count); + self->mempos += count; + if (self->mempos > self->memlen) self->memlen = self->mempos; + + return members; +} + +static int +memapi_flush(gbfile *self) +{ + return 0; +} + +static gbsize_t +memapi_tell(gbfile *self) +{ + return self->mempos; +} + +static int +memapi_eof(gbfile *self) +{ + return (self->mempos == self->memlen); +} + +static int +memapi_ungetc(const int c, gbfile *self) +{ + if (self->mempos == 0) return EOF; + else { + self->mempos--; + self->handle.mem[self->mempos] = (unsigned char) c; + return c; + } +} + +static void +memapi_clearerr(gbfile *self) +{ + return; +} + +static int +memapi_error(gbfile *self) +{ + return 0; +} + + /* GPSBabel 'file' standard calls */ /* @@ -65,12 +470,11 @@ gbfopen(const char *filename, const char *mode, const char *module) file = xcalloc(1, sizeof(*file)); - file->name = xstrdup(filename); file->module = xstrdup(module); - file->line = xstrdup(""); file->mode = 'r'; // default file->binary = (strchr(mode, 'b') != NULL); file->back = -1; + file->memapi = (filename == NULL); for (m = mode; *m; m++) { switch(tolower(*m)) { @@ -85,55 +489,74 @@ gbfopen(const char *filename, const char *mode, const char *module) break; } } + + if (file->memapi) { + file->gzapi = 0; + file->name = xstrdup("(Memory stream)"); + + file->fileclearerr = memapi_clearerr; + file->fileclose = memapi_close; + file->fileeof = memapi_eof; + file->fileerror = memapi_error; + file->fileflush = memapi_flush; + file->fileopen = memapi_open; + file->fileread = memapi_read; + file->fileseek = memapi_seek; + file->filetell = memapi_tell; + file->fileungetc = memapi_ungetc; + file->filewrite = memapi_write; + } + else { + file->name = xstrdup(filename); + file->is_pipe = (strcmp(filename, "-") == 0); - /* Do we have a '.gz' extension in the filename ? */ - len = strlen(file->name); - if ((len > 3) && (case_ignore_strcmp(&file->name[len-3], ".gz") == 0)) { + /* Do we have a '.gz' extension in the filename ? */ + len = strlen(file->name); + if ((len > 3) && (case_ignore_strcmp(&file->name[len-3], ".gz") == 0)) { #if !ZLIB_INHIBITED - /* force gzipped files on output */ - file->gzapi = 1; + /* force gzipped files on output */ + file->gzapi = 1; #else - fatal(NO_ZLIB); + fatal(NO_ZLIB); #endif - } - - if (file->gzapi) { -#if !ZLIB_INHIBITED - char openmode[32]; + } - /* under non-posix systems files MUST be opened in binary mode */ - - strcpy(openmode, mode); - if (strchr(mode, 'b') == NULL) - strncat(openmode, "b", sizeof(openmode)); + if (file->gzapi) { +#if !ZLIB_INHIBITED - if (strcmp(filename, "-") == 0) { - FILE *fd; - if (file->mode == 'r') - fd = stdin; - else - fd = stdout; - SET_BINARY_MODE(fd); - file->handle.gz = gzdopen(fileno(fd), openmode); - } - else - file->handle.gz = gzopen(filename, openmode); - - if (file->handle.gz == NULL) { - fatal("%s: Cannot %s file '%s'!\n", - module, - (file->mode == 'r') ? "open" : "create", - filename); - } - file->gzapi = 1; + file->fileclearerr = gzapi_clearerr; + file->fileclose = gzapi_close; + file->fileeof = gzapi_eof; + file->fileerror = gzapi_error; + file->fileflush = gzapi_flush; + file->fileopen = gzapi_open; + file->fileread = gzapi_read; + file->fileseek = gzapi_seek; + file->filetell = gzapi_tell; + file->fileungetc = gzapi_ungetc; + file->filewrite = gzapi_write; #else - /* This is the only runtime test we make */ - fatal("%s: Zlib was not included in this build.\n", file->module); + /* This is the only runtime test we make */ + fatal("%s: Zlib was not included in this build.\n", file->module); #endif + } + else { + file->fileclearerr = stdapi_clearerr; + file->fileclose = stdapi_close; + file->fileeof = stdapi_eof; + file->fileerror = stdapi_error; + file->fileflush = stdapi_flush; + file->fileopen = stdapi_open; + file->fileread = stdapi_read; + file->fileseek = stdapi_seek; + file->filetell = stdapi_tell; + file->fileungetc = stdapi_ungetc; + file->filewrite = stdapi_write; + } } - else { - file->handle.std = xfopen(filename, mode, module); - } + + file->fileopen(file, mode); + #ifdef DEBUG_MEM file->buffsz = 1; #else @@ -167,20 +590,11 @@ void gbfclose(gbfile *file) { if (!file) return; + + file->fileclose(file); - if (file->gzapi) { -#if !ZLIB_INHIBITED - gzclose(file->handle.gz); -#else - fatal(NO_ZLIB); -#endif - } - else { - fclose(file->handle.std); - } xfree(file->name); xfree(file->module); - xfree(file->line); xfree(file->buff); xfree(file); } @@ -240,57 +654,7 @@ gbsize_t gbfread(void *buf, const gbsize_t size, const gbsize_t members, gbfile *file) { if ((size == 0) || (members == 0)) return 0; - - if (file->gzapi) { -#if !ZLIB_INHIBITED - int result = 0; - char *target = buf; - int count = size * members; - - if (file->back != -1) { - *target++ = file->back; - count--; - result++; - file->back = -1; - } - result += gzread(file->handle.gz, target, count); - - /* Check for an incomplete READ */ - if ((members == 1) && (size > 1) && (result > 0) && (result < (int)size)) - fatal("%s: Unexpected end of file (EOF)!\n", file->module); - - result /= size; - - if ((result < 0) || ((gbsize_t)result < members)) { - int errnum; - const char *errtxt; - - errtxt = gzerror(file->handle.gz, &errnum); - - /* Workaround for zlib bug: buffer error on empty files */ - if ((errnum == Z_BUF_ERROR) && (gztell(file->handle.gz) == 0)) { - return (gbsize_t) 0; - } - if ((errnum != Z_STREAM_END) && (errnum != 0)) - fatal("%s: zlib returned error %d ('%s')!\n", - file->module, errnum, errtxt); - } - return (gbsize_t) result; -#else - fatal(NO_ZLIB); - return -1; -#endif - } - else { - int errno; - gbsize_t result = fread(buf, size, members, file->handle.std); - - if ((result < members) && (errno = ferror(file->handle.std))) { - fatal("%s: Error %d occured during read of file '%s'!\n", - file->module, errno, file->name); - } - return result; - } + return file->fileread(buf, size, members, file); } /* @@ -383,25 +747,13 @@ gbfwrite(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *f { int result; - if ((size == 0) || (members == 0)) return 0; - - if (file->gzapi) { -#if !ZLIB_INHIBITED - result = gzwrite(file->handle.gz, buf, size * members) / size; -#else - fatal(NO_ZLIB); - return -1; -#endif - } - else { - result = fwrite(buf, size, members, file->handle.std); - } - + result = file->filewrite(buf, size, members, file); if (result != members) { - fatal("%s: Could not write %lld bytes to %s!\n", + fatal("%s: Could not write %lld bytes to %s (result %d)!\n", file->module, (long long int) (members - result) * size, - file->name); + file->name, + result); } return result; @@ -414,17 +766,7 @@ gbfwrite(const void *buf, const gbsize_t size, const gbsize_t members, gbfile *f int gbfflush(gbfile *file) { - if (file->gzapi) { -#if !ZLIB_INHIBITED - return gzflush(file->handle.gz, Z_SYNC_FLUSH); -#else - fatal(NO_ZLIB); - return -1; -#endif - } - else { - return fflush(file->handle.std); - } + return file->fileflush(file); } /* @@ -434,16 +776,7 @@ gbfflush(gbfile *file) void gbfclearerr(gbfile *file) { - if (file->gzapi) { -#if !ZLIB_INHIBITED - gzclearerr(file->handle.gz); -#else - fatal(NO_ZLIB); -#endif - } - else { - clearerr(file->handle.std); - } + file->fileclearerr(file); } /* @@ -453,20 +786,7 @@ gbfclearerr(gbfile *file) int gbferror(gbfile *file) { - int errnum; - - if (file->gzapi) { -#if !ZLIB_INHIBITED - (void)gzerror(file->handle.gz, &errnum); -#else - fatal(NO_ZLIB); - return -1; -#endif - } - else { - errnum = ferror(file->handle.std); - } - return errnum; + return file->fileerror(file); } /* @@ -487,46 +807,7 @@ gbfrewind(gbfile *file) int gbfseek(gbfile *file, gbint32 offset, int whence) { - int result; - - if (file->gzapi) { - - assert(whence != SEEK_END); - -#if !ZLIB_INHIBITED - if ((whence == SEEK_CUR) && (file->back != -1)) offset--; - result = gzseek(file->handle.gz, offset, whence); - file->back = -1; -#else - result = 1; -#endif - if (result < 0) { - if (strcmp(file->name, "-") == 0) - fatal("%s: This format cannot be used in piped commands!\n", file->module); - fatal("%s: online compression not yet supported for this format!", file->module); - } - return 0; - } - else { - gbsize_t pos = 0; - - if (whence != SEEK_SET) pos = ftell(file->handle.std); - - result = fseek(file->handle.std, offset, whence); - if (result != 0) { - switch (whence) { - case SEEK_CUR: - case SEEK_END: pos = pos + offset; break; - case SEEK_SET: pos = offset; break; - default: - fatal("%s: Unknown seek operation (%d) for file %s!\n", - file->module, whence, file->name); - } - fatal("%s: Unable to set file (%s) to position (%llu)!\n", - file->module, file->name, (long long unsigned) pos); - } - return 0; - } + return file->fileseek(file, offset, whence); } /* @@ -536,23 +817,7 @@ gbfseek(gbfile *file, gbint32 offset, int whence) gbsize_t gbftell(gbfile *file) { - gbsize_t result; - - if (file->gzapi) { -#if !ZLIB_INHIBITED - result = gztell(file->handle.gz); - if (file->back != -1) { -// file->back = -1; - result--; - } -#else - fatal(NO_ZLIB); - result = -1; -#endif - } - else { - result = ftell(file->handle.std); - } + gbsize_t result = file->filetell(file); if ((signed) result == -1) fatal("%s: Could not determine position of file '%s'!\n", file->module, file->name); @@ -566,38 +831,7 @@ gbftell(gbfile *file) int gbfeof(gbfile *file) { - if (file->gzapi) { -#if !ZLIB_INHIBITED - int res; - - if (file->back != -1) return 0; - - res = gzeof(file->handle.gz); - if (!res) { - unsigned char test; - int len = gzread(file->handle.gz, &test, 1); - if (len == 1) { - /* No EOF, put the single byte back into stream */ - file->back = test; - } - else { - /* we are at the end of the file */ - if (global_opts.debug_level > 0) { - /* now gzeof() should return 1 */ - is_fatal(!gzeof(file->handle.gz), "zlib gzeof error!\n"); - } - res = 1; - } - } - return res; -#else - fatal(NO_ZLIB); - return 0; -#endif - } - else { - return feof(file->handle.std); - } + return file->fileeof(file); } /* @@ -607,25 +841,7 @@ gbfeof(gbfile *file) int gbfungetc(const int c, gbfile *file) { - int res; - - if (file->gzapi) { -#if !ZLIB_INHIBITED - if (file->back == -1) { - file->back = c; - res = c; - } - else { - fatal(MYNAME ": Cannot store more than one byte back!\n"); - } -#else - fatal(NO_ZLIB); -#endif - } - else { - res = ungetc(c, file->handle.std); - } - return res; + return file->fileungetc(c, file); } /* GPSBabel 'file' enhancements */ @@ -754,7 +970,7 @@ static char * gbfgetucs2str(gbfile *file) { int len = 0; - char *result = file->line; + char *result = file->buff; for (;;) { char buff[8]; @@ -778,9 +994,9 @@ gbfgetucs2str(gbfile *file) clen = cet_ucs4_to_utf8(buff, sizeof(buff), c); - if (len+clen >= file->linesz) { - file->linesz += 64; - result = file->line = xrealloc(file->line, file->linesz + 1); + if (len+clen >= file->buffsz) { + file->buffsz += 64; + result = file->buff = xrealloc(file->buff, file->buffsz + 1); } memcpy(&result[len], buff, clen); len += clen; @@ -799,7 +1015,7 @@ char * gbfgetstr(gbfile *file) { int len = 0; - char *result = file->line; + char *result = file->buff; if (file->unicode) return gbfgetucs2str(file); @@ -842,9 +1058,9 @@ gbfgetstr(gbfile *file) file->unicode_checked = 1; - if (len == file->linesz) { - file->linesz += 64; - result = file->line = xrealloc(file->line, file->linesz + 1); + if (len == file->buffsz) { + file->buffsz += 64; + result = file->buff = xrealloc(file->buff, file->buffsz + 1); } result[len] = (char)c; len++; @@ -950,5 +1166,25 @@ gbfputpstr(const char *s, gbfile *file) return (len + 1); } +/* Much more higher level functions */ + +gbsize_t +gbfcopyfrom(gbfile *file, gbfile *src, gbsize_t count) +{ + char buf[1024]; + gbsize_t copied = 0; + + while (count) { + gbsize_t n = gbfread(buf, 1, (count < sizeof(buf)) ? count : sizeof(buf), src); + if (n > 0) { + gbfwrite(buf, 1, n, file); + count -= n; + copied += n; + } + else break; + } + return copied; +} + /* Thats all, sorry. */ diff --git a/gpsbabel/gbfile.h b/gpsbabel/gbfile.h index d13e24a05..639aa7bd4 100644 --- a/gpsbabel/gbfile.h +++ b/gpsbabel/gbfile.h @@ -2,7 +2,7 @@ Common GPSBabel file I/O API - Copyright (C) 2006 Olaf Klein + Copyright (C) 2006,2007,2008 Olaf Klein, o.b.klein@gpsbabel.org This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -30,30 +30,60 @@ #include "defs.h" #include "cet.h" +struct gbfile_s; +typedef struct gbfile_s gbfile; + +typedef void (*gbfclearerr_cb) (gbfile *self); +typedef int (*gbfclose_cb) (gbfile *self); +typedef int (*gbfeof_cb) (gbfile *self); +typedef int (*gbferror_cb) (gbfile *self); +typedef int (*gbfflush_cb) (gbfile *self); +typedef gbfile* (*gbfopen_cb) (gbfile *self, const char *mode); +typedef gbsize_t (*gbfread_cb) (void *buf, const gbsize_t size, const gbsize_t members, gbfile *self); +typedef int (*gbfseek_cb) (gbfile *self, gbint32 offset, int whence); +typedef gbsize_t (*gbftell_cb) (gbfile *self); +typedef gbsize_t (*gbfwrite_cb) (const void *buf, const gbsize_t size, const gbsize_t members, gbfile *self); +typedef int (*gbfungetc_cb) (const int c, gbfile *self); + typedef struct gbfile_s { #ifdef DEBUG_MEM void *dummy; /* ZERO pointer for stdio oop's */ #endif union { FILE *std; + unsigned char *mem; #if !ZLIB_INHIBITED gzFile *gz; #endif } handle; char *name; char *module; - char *line; - int linesz; char *buff; /* static growing buffer, primary used by gbprintf */ int buffsz; char mode; int back; + gbsize_t mempos; /* curr. position in memory */ + gbsize_t memlen; /* max. number of written bytes to memory */ + gbsize_t memsz; /* curr. size of allocated memory */ unsigned char big_endian:1; unsigned char binary:1; unsigned char gzapi:1; + unsigned char memapi:1; unsigned char unicode:1; unsigned char unicode_checked:1; -} gbfile; + unsigned char is_pipe:1; + gbfclearerr_cb fileclearerr; + gbfclose_cb fileclose; + gbfeof_cb fileeof; + gbferror_cb fileerror; + gbfflush_cb fileflush; + gbfopen_cb fileopen; + gbfread_cb fileread; + gbfseek_cb fileseek; + gbftell_cb filetell; + gbfungetc_cb fileungetc; + gbfwrite_cb filewrite; +} gbfile_t; gbfile *gbfopen(const char *filename, const char *mode, const char *module); @@ -100,4 +130,6 @@ int gbfputflt(const float f, gbfile *file); // write a float value int gbfputcstr(const char *s, gbfile *file); // write string including '\0' int gbfputpstr(const char *s, gbfile *file); // write as pascal string +gbsize_t gbfcopyfrom(gbfile *file, gbfile *src, gbsize_t count); + #endif -- 2.30.2